package com.zhl.study.countDownLatch;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @description CountDownLatc 使用demo
 * CountDownLatch 是一个同步辅助工具，允许一个或多个线程等待，直到在其他线程中执行的一组操作完成。
 * 使用场景：
 *      等待某些初始化操作完成后再执行主任务。
 *      并行任务的协调，例如等待所有子任务完成后再执行汇总任务。
 *      模拟并发测试。
 * 构造方法:
 *      使用指定的计数器值初始化 CountDownLatch 的实例。计数器的初始值表示需要等待的任务数量。
 * await() 方法
 *      这是一个阻塞方法,它会阻塞当前线程,直到计数器的值被递减为0。常用于一个线程等待其他多个线程完成某些操作后再执行。
 * await(long timeout, TimeUnit unit)
 *      重载的 await 方法,增加了超时等待时间。如果指定的时间内计数器的值仍未被递减为0,则方法返回 false,否则返回 true。
 * countDown() 方法
 *      每次调用这个方法,计数器的值就会减1。通常在线程完成某个操作后调用该方法,将计数器减1,表示有一个任务已经完成了。当计数器的值被递减为0时,那些因调用 await() 方法而阻塞的线程就会被唤醒继续执行。
 * getCount() 方法
 *      返回当前计数器的值。
 * @Author: z156940l@outlook.com
 * @className CountDownLatchDemo
 * @Date: 2024/5/22 17:41
 */
@Slf4j
public class CountDownLatchDemo {

    /**
     * 同时启动三个线程
     */
    public void startThreadsSimultaneously() {
        // 创建一个 CountDownLatch，计数器为1
        CountDownLatch startSignal = new CountDownLatch(1);
        // 创建三个线程，并在线程中等待 CountDownLatch 的释放
        Thread threadA = new Thread(() -> {
            try {
                startSignal.await(); // 等待 CountDownLatch 变为0
                log.info("Thread A is running, currentTime:{}", System.currentTimeMillis());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread threadB = new Thread(() -> {
            try {
                startSignal.await(); // 等待 CountDownLatch 变为0
                log.info("Thread B is running, currentTime:{}", System.currentTimeMillis());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread threadC = new Thread(() -> {
            try {
                startSignal.await(); // 等待 CountDownLatch 变为0
                log.info("Thread C is running, currentTime:{}", System.currentTimeMillis());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 启动三个线程
        threadA.start();
        threadB.start();
        threadC.start();

        // 主线程暂停，确保所有线程都已启动并在等待
        try {
            //确保所有线程都已启动并在等待
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 释放 CountDownLatch，所有等待的线程将同时开始执行
        startSignal.countDown();
    }

    /**
     * 并行计算的线程同步
     */
    public void threadSynchronizationInParallelComputing() {
        int numThreads = 5;
        CountDownLatch latch = new CountDownLatch(numThreads);
        ExecutorService executor = Executors.newFixedThreadPool(numThreads);

        for (int i = 0; i < numThreads; i++) {
            executor.execute(() -> {
                performComputation();
                latch.countDown(); // 计算线程完成后递减计数器
            });
        }

        try {
            latch.await(); // 主线程等待所有计算线程完成
            log.info("All computations completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executor.shutdown();
    }

    /**
     * 启动多个线程后等待结束
     */
    public void waitingForThreadToEnd() {
        int numThreads = 20;
        CountDownLatch latch = new CountDownLatch(numThreads);

        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                doWork();
                latch.countDown(); // 工作线程完成后递减计数器
            }).start();
        }

        try {
            latch.await(); // 主线程等待所有工作线程结束
            log.info("All threads completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步多线程的开始时间
     */
    public void startTimeOfSynchronizationThread() {
        int numThreads = 5;
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(numThreads);

        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    startLatch.await(); // 工作线程等待startLatch的countDown信号
                    doWork();
                    endLatch.countDown(); // 工作线程完成后递减endLatch计数器
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        log.info("All threads ready, start working...");
        startLatch.countDown(); // 主线程发送startLatch的countDown信号

        try {
            endLatch.await(); // 主线程等待所有工作线程结束
            log.info("All threads completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 分布式操作的协调
     */
    public void coordinationOfDistributedOperations() {
        int numNodes = 3;
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(numNodes);

        for (int i = 0; i < numNodes; i++) {
            new Thread(() -> {
                try {
                    startLatch.await(); // 子系统等待startLatch的countDown信号
                    performOperation();
                    endLatch.countDown(); // 子系统完成后递减endLatch计数器
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        log.info("All nodes ready, start operation...");
        startLatch.countDown(); // 主线程发送startLatch的countDown信号
        try {
            endLatch.await(); // 主线程等待所有子系统完成
            log.info("All nodes completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试场景的控制
     */
    public void controlOfTestingScenarios() {
        int numThreads = 5;
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch workLatch = new CountDownLatch(numThreads);

        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    startLatch.await(); // 测试线程等待startLatch的countDown信号
                    doWork();
                    workLatch.countDown(); // 测试线程完成后递减workLatch计数器
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        log.info("All threads ready, start testing...");
        startLatch.countDown(); // 主线程发送startLatch的countDown信号

        try {
            workLatch.await(); // 主线程等待所有测试线程结束
            log.info("All tests completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行分布式操作
     */
    private void performOperation() {
        // 执行分布式操作
        log.info("当前线程：{},开始执行时间:{}", Thread.currentThread(), System.currentTimeMillis());
    }

    /**
     * 执行一些耗时操作
     */
    private void doWork() {
        // 执行一些耗时操作
        log.info("当前线程：{},开始执行时间:{}", Thread.currentThread(), System.currentTimeMillis());
    }

    /**
     * 执行一些复杂的计算操作
     */
    private void performComputation() {
        // 执行一些复杂的计算操作
        log.info("当前线程：{},开始执行时间:{}", Thread.currentThread(), System.currentTimeMillis());
    }
}
